﻿#include <cstdio>
#include  "UserServer.h"
#include "define_protocol.h"
#include <unistd.h>
#include "public.h"
#include "cCConfig.h"
#include <fcntl.h>
#include <dlfcn.h>
#include <mysql_connect.h>
#include <mysql_execute.h>
#include <sys/stat.h>

#include <semaphore.h>  //信号量

size_t                         	        g_TcpHeaderSize;
size_t                         	        g_TcpMsgSize;
CUserServer             		    *g_pServer;

RsaKeyGenerate					pRsaKeyGenerate = nullptr;
RsaKeyGenerateInit			pRsaKeyGenerateInit = nullptr;
RsaEncrypt						    g_pRsaEncrypt = nullptr;
RsaDecrypt						    g_pRsaDecrypt = nullptr;
RsaDecrypt2						g_pRsaDecrypt2 = nullptr;
sem_t                                  g_SemExitApp;                   //
void get_time_ymdhs();

int InitSqlConnection();

int   InitEncryLib();


void get_time_ymdhs()
{
    time_t timep;
    struct tm* p;
    time(&timep);
    p = localtime(&timep);
    printf("time:%d-%d-%d %d:%d:%d week:%d\n", (1900 + p->tm_year), (1 + p->tm_mon), p->tm_mday, (p->tm_hour), p->tm_min, p->tm_sec, p->tm_wday);
}

int InitSqlConnection()
{
    //return  1;
    printf("InitSqlConnection --begin\n");
    CConfig* p_config = CConfig::GetInstance();

    char pIp[64] = { 0 };
    strcpy(pIp, p_config->GetString("dbIP"));

    int dbport = p_config->GetIntDefault("Port", 3306);              //epoll连接的最大项数


    char pUser[64] = { 0 };
    strcpy(pUser, p_config->GetString("User"));

    char  pPwd[64] = { 0 };
    strcpy(pPwd, p_config->GetString("Pwd"));

    char pDBName[64] = { 0 };
    strcpy(pDBName, p_config->GetString("DBName"));

    printf("mysql Info---------------------- ::%s %d %s %s %s\n", pIp, dbport, pUser, pPwd, pDBName);
    if (mysql_connect::get()->mysql_init(15, pIp, dbport, pUser, pPwd, pDBName) == 1)
    {
        return 1;
    }

    return  0;
}

int   InitEncryLib()
{
    void* libm_handle = nullptr;
    char* errorInfo;
   // float result;
    libm_handle = dlopen("libshove.so", RTLD_LAZY);
    if (!libm_handle)
    {
        printf("Open Error:%s.\n", dlerror());
        return 0;
    }
    pRsaKeyGenerateInit = (RsaKeyGenerateInit)dlsym(libm_handle, "RsaKeyGenerateInit");
    pRsaKeyGenerate = (RsaKeyGenerate)dlsym(libm_handle, "rsaKeyGenerate");
    g_pRsaEncrypt = (RsaEncrypt)dlsym(libm_handle, "rsaEncrypt");
    g_pRsaDecrypt = (RsaDecrypt)dlsym(libm_handle, "rsaDecrypt");
    g_pRsaDecrypt2 = (RsaDecrypt2)dlsym(libm_handle, "rsaDecryptEx");

    printf("InitEncryLib:%p %p \n", g_pRsaDecrypt, g_pRsaDecrypt2);
    errorInfo = dlerror();// 调用dlerror方法，返回错误信息的同时，内存中的错误信息被清空
    if (errorInfo != nullptr)
    {
        printf("Dlsym Error:%s.\n", errorInfo);
        return 0;
    }

    return 0;
}


int ngx_daemon()
{

    switch (fork())
    {
    case -1:
        return -1;
    case 0:
        break;
    default:

        return 1;  //父进程直接返回1；
    } //end 

   //只有fork()出来的子进程才能走到这个流程
   // ngx_pid = getpid();             //当前子进程的id要重新取得    
   //说明：当进程是会话组长时setsid()调用失败。但第一点已经保证进程不是会话组长。
   //setsid()调用成功后，进程成为新的会话组长和新的进程组长，并与原来的登录会话和进程组脱离。由于会话过程对控制终端的独占性，进程同时与控制终端脱离
    if (setsid() == -1)
    {
        return -1;
    }
	
    //(3)设置为0，不要让它来限制文件权限，以免引起混乱
    umask(0);
    //return 0; //子进程返回0
    //(4)打开黑洞设备，以读写方式打开
    int fd = open("/dev/null", O_RDWR);
    if (fd == -1)
    {
        printf("ngx_daemon()中open(\"/dev/nullptr\")失败! \n");
        return -1;
    }
    if (dup2(fd, STDIN_FILENO) == -1) //先关闭STDIN_FILENO[这是规矩，已经打开的描述符，动他之前，先close]，类似于指针指向nullptr，让/dev/nullptr成为标准输入；
    {
        printf("ngx_daemon()中dup2(STDIN)失败! \n");
        return -1;
    }
    if (dup2(fd, STDOUT_FILENO) == -1) //再关闭STDIN_FILENO，类似于指针指向nullptr，让/dev/nullptr成为标准输出；
    {
        printf("ngx_daemon()中dup2(STDOUT)失败! \n");
        return -1;
    }
    if (fd > STDERR_FILENO)  //fd应该是3，这个应该成立
    {
        if (close(fd) == -1)  //释放资源这样这个文件描述符就可以被复用；不然这个数字【文件描述符】会被一直占着；
        {
            printf("ngx_daemon()中close(fd)失败! \n");
            return -1;
        }
    }
    return 0; //子进程返回0
}

static void sighandler1(int sig_no)
{
    printf("sighandler1 exit!\n");
    exit(0);
}

bool  g_bExit = false;
static void sighandler2(int sig_no)
{    
    printf("sighandler2 g_pServer->Stop()!\n");

    g_pServer->Stop();
    if (g_pServer)
    {
        delete          g_pServer;

        g_pServer = nullptr;
    }
    g_bExit = true;
    sem_post(&g_SemExitApp);
}


int main(int argc, char* const* argv)
{
    int  nDaemon = 0;
    if (argc == 2)
    {
        nDaemon = atoi(argv[1]);
    }
    sem_init(&g_SemExitApp, 0, 0);
    if (nDaemon == 1)
    {
        int cdaemonresult = ngx_daemon();

        if (cdaemonresult == 1)
        {
            return 1;  //整个进程直接在这里退出
        }
    }
	/*
	sigaddset(&set, SIGCHLD);     //子进程状态改变
	sigaddset(&set, SIGALRM);     //定时器超时
	sigaddset(&set, SIGIO);       //异步I/O
	sigaddset(&set, SIGINT);      //终端中断符
	sigaddset(&set, SIGHUP);      //连接断开
	sigaddset(&set, SIGWINCH);    //终端窗口大小改变
	sigaddset(&set, SIGTERM);     //终止
	sigaddset(&set, SIGQUIT);     //终端退出符
	*/
    signal(SIGUSR2, sighandler2);	
    
	signal(SIGPIPE, SIG_IGN);                                                            //SIG_IGN,系统函数，忽略信号的处理程序,客户端发送RST包后，服务器还调用write会触发
	signal(SIGCHLD,SIG_IGN);
	signal(SIGALRM,SIG_IGN);	
	signal(SIGIO,SIG_IGN);
	signal(SIGINT,SIG_IGN);
	signal(SIGHUP,SIG_IGN);
	signal(SIGWINCH,SIG_IGN);
	signal(SIGTERM,SIG_IGN);
	signal(SIGQUIT,SIG_IGN);
	
	printf("Version 1.0\r\n");
    get_time_ymdhs();
#ifndef  VSdebug
    CConfig* p_config = CConfig::GetInstance();

    if (p_config->Load("config.conf") == false) //把配置文件内容载入到内存            
    {
        printf(" load nginx.conf error\n");
    }
    else
    {
        printf(" load nginx.conf ok\n");
    }
    InitSqlConnection();

    InitEncryLib();
    {
        char key[512] = { 0 };       
        if (pRsaKeyGenerate != nullptr)
        {
            (*pRsaKeyGenerate)(512, key);
        }
        printf("%s\n", key);
    }

#endif // VS


    g_TcpHeaderSize = sizeof(NET_TCP_HEAD);

    g_TcpMsgSize = sizeof(_STRUC_MSG_HEADER);

    CUserServer* pServer = new  CUserServer;
    pServer->InitData();
    pServer->Start(58888,2);

    g_pServer = pServer;
	
    
    while (1)
    {
        //printf("sem_wait LoopBeg\r\n");
        if (sem_wait(&g_SemExitApp) != -1)
        {
            //break;
        }
        //printf("sem_wait LoopEnd\r\n");
        sleep(5);
    }
lblexit:
    printf("lblexit  Exit!\n");
    return 0;
}